package impl

import (
	"context"
	"fmt"

	"github.com/infraboard/mcube/v2/exception"
	"github.com/infraboard/mcube/v2/ioc"
	"github.com/infraboard/mcube/v2/ioc/config/datasource"
	"github.com/infraboard/mcube/v2/ioc/config/log"
	"gitlab.com/go-course-project/go17/vblog/apps/token"
	"gitlab.com/go-course-project/go17/vblog/apps/user"
)

func init() {
	ioc.Controller().Registry(&TokenServiceImpl{})
}

// 定义一个struct, 用于实现 UserService就是刚才定义的接口
// 怎么才能判断这个结构体没有实现这个接口
type TokenServiceImpl struct {
	ioc.ObjectImpl

	// user service
	user user.AdminService

	// 如果你控制器有一些配置
	DefaultExpiredTTL int `json:"default_expired_ttl" yaml:"default_expired_ttl" toml:"default_expired_ttl" env:"DEFAULT_EXPIRED_TTL"`
}

func (*TokenServiceImpl) Name() string {
	return token.AppName
}

// 他需要自己去获取依赖，通过ioc
func (i *TokenServiceImpl) Init() error {
	i.user = user.GetService()

	log.L().Debug().Msgf("DefaultExpiredTTL: %d", i.DefaultExpiredTTL)
	return nil
}

// IssueToken implements token.Service.
func (t *TokenServiceImpl) IssueToken(ctx context.Context, in *token.IssueTokenRequest) (*token.Token, error) {
	if err := in.Validate(); err != nil {
		return nil, exception.NewBadRequest("参数校验异常: %s", err)
	}
	// 1. 查询用户
	u, err := t.user.DescribeUser(ctx, &user.DescribeUserRequest{
		DescribeBy: user.DESCRIBE_BY_USERNAME,
		Value:      in.Username,
	})
	if err != nil {
		if exception.IsNotFoundError(err) {
			return nil, exception.NewUnauthorized("用户名或者密码错误").WithData(err)
		}
		return nil, err
	}

	// 2. 比对密码
	if err := u.CheckPassword(in.Password); err != nil {
		return nil, exception.NewUnauthorized("用户名或者密码错误").WithData(err)
	}

	// 3. 颁发Token
	tk := token.NewToken(fmt.Sprintf("%d", u.Id)).SetRefUserName(u.Username)

	// if in.RememberMe {
	// 	tk.AccessTokenExpireAt
	// }

	if err := datasource.DBFromCtx(ctx).Create(tk).Error; err != nil {
		return nil, err
	}

	return tk, nil
}

// RevolkToken implements token.Service.
func (t *TokenServiceImpl) RevolkToken(context.Context, *token.RevolkTokenRequest) (*token.Token, error) {
	panic("unimplemented")
}

// ValidateToken implements token.Service.
// 1. 这个令牌是不是我们发
// 2. 这个令牌有没有过期
func (t *TokenServiceImpl) ValidateToken(ctx context.Context, in *token.ValidateTokenRequest) (*token.Token, error) {
	tk := &token.Token{}
	if err := datasource.DBFromCtx(ctx).Where("access_token = ?", in.AccessToken).Take(tk).Error; err != nil {
		return nil, err
	}

	if err := tk.IsAccessTokenExpired(); err != nil {
		return nil, err
	}

	// 1. 补充用户信息
	u, err := t.user.DescribeUser(ctx, &user.DescribeUserRequest{
		DescribeBy: user.DESCRIBE_BY_ID,
		Value:      tk.RefUserId,
	})
	if err != nil {
		return nil, err
	}
	tk.RefUserName = u.Username
	return tk, nil
}
